import sys
import os
import objc

from objc import YES, NO, NULL

UIKit = objc.loadBundle("UIKit", globals(), "/System/Library/Frameworks/UIKit.framework")
objc.loadBundleFunctions(UIKit, globals(), [("UIApplicationMain", "iii@@"),])
_UIApplicationMain = UIApplicationMain
def UIApplicationMain(argv=None, principal=objc.nil, delegate=None):
    if argv == None:
        import sys
        argv = sys.argv

        from ctypes import c_char_p, addressof
        argc = len(argv)
        argv = (c_char_p * argc)(*argv)

        if delegate is None:
            delegate = principal

        if principal != objc.nil:
            principal = NSString.alloc().initWithString_(principal.__name__)
        if delegate != objc.nil:
            delegate = NSString.alloc().initWithString_(delegate.__name__)

        return _UIApplicationMain(argc, addressof(argv), principal, delegate)
   
class PYApplication(UIApplication):
    currentMenu = 0         #  0 for  Map/Route List - 1 for settings
    path        = None
    
    ImportAlert = None
    aboutAlert  = None
    instrAlert  = None
    processAlert = None

    dispMenu     = []       # displayed menu
    settingsMenu = []       # prepared settings menu
    mainMenu     = []       # prepared main menu
    
    mapItems   = []         # list of Maps
    routeItems = []         # list of Routes
    cmdItems   = []         # list of Setting Comands
    

    # version number a.b.c-d
    # -> b : for the major code change 
    # -> c : for UI change 
    # -> d : counting the package building times

    version_number = "v2.0.0"
    version    = "iPhone Offline Maps " + version_number
    # -------------------------------------------------------------------------------------
    def string(self, s):
        return NSBundle.mainBundle().localizedStringForKey_value_table_(s, "", None)

    # -------------------------------------------------------------------------------------
    @objc.signature("i@:@")
    def numberOfSectionsInTableView_(self, list):
        return len(self.dispMenu)

    @objc.signature("i@:@i")
    def tableView_numberOfRowsInSection_(self, table, section):
        return len(self.dispMenu[section]["items"])

    @objc.signature("i@:@@")
    def tableView_canEditRowAtIndexPath_(self, table,  path):
        # Cells are editable only if the table is in edition mode (prevent delete to appear if user swipe on a row)
        return table.isEditing()

    @objc.signature("@@:@@")
    def tableView_cellForRowAtIndexPath_(self, table,  path):
        cell = table.dequeueReusableCellWithIdentifier_("PYApplication")
        if cell == None:
            zrect = ((0, 0), (0, 0))
            cell =  UITableViewCell.alloc().initWithFrame_reuseIdentifier_(zrect, "PYApplication")

        # zrect = ((0, 0), (0, 0))
        # cell =  UITableViewCell.alloc().initWithFrame_(zrect)

        myLabel = cell.viewWithTag_(10)
        try:
            size = self.dispMenu[path.section()]["items"][path.row()]["info"] 
        except:
            size = None

        cellRect = cell.bounds()
        x = 35
        if self.table.isEditing():
            x = 15
        if myLabel == None:
            myLabel = UILabel.alloc().initWithFrame_((((cellRect[1][0]/3)*2,cellRect[0][1]+5), ((cellRect[1][0]/3)-x,cellRect[1][1]-10)))
            myLabel.setTag_(10)
#            myColor = UIColor.alloc().initWithRed_green_blue_alpha_(0.0,0.15,0.65,0.9)
            myColor = UIColor.alloc().initWithRed_green_blue_alpha_(0.0,0.141,0.588,1)
            myLabel.setTextColor_(myColor)
            myLabel.setTextAlignment_(2)
            cell.addSubview_(myLabel)
        
        if size == None:
            myLabel.setFrame_((((cellRect[1][0]/3)*3,cellRect[0][1]+5), ((cellRect[1][0]/3)-x,cellRect[1][1]-10)))
        else:
            myLabel.setFrame_((((cellRect[1][0]/3)*2,cellRect[0][1]+5), ((cellRect[1][0]/3)-x,cellRect[1][1]-10)))
            myLabel.setText_(size + " ")
        
        if self.currentMenu == 0:
            cell.setAccessoryType_(1)
        else:
            cell.setAccessoryType_(0)
        
        try:
            badge = self.dispMenu[path.section()]["items"][path.row()]["badge"] 
        except:
            badge = None
            
        if (self.currentMenu == 0) and (badge != None) and (self.applicationBadge() == badge):
            cell.setTextColor_(UIColor.alloc().initWithRed_green_blue_alpha_(0.75,0,0,1))
        else:
            cell.setTextColor_(UIColor.blackColor())
            
        cell.setText_(self.dispMenu[path.section()]["items"][path.row()]["name"])
        return cell

    @objc.signature("@@:@i")
    def tableView_titleForHeaderInSection_(self, table, section):
        return self.string(self.dispMenu[section]["section"])
    
    # (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
    @objc.signature("v@:@@")
    def tableView_didSelectRowAtIndexPath_(self, table, path):
        self.path = path

        select = self.path.section()
        row    = self.path.row()

        # in edition mode, first row is for import
        if (table.isEditing() == True) and (row == 0):
            self.iomsDisplayImportAlert(path.section())
            return
        
        section = self.dispMenu[ select ]["section"]
        if section == "Infos":
            title  = self.dispMenu[ select ]["items"][row]["name"]
            
            if title == self.string("About"):
                self.aboutAlert.show()
            else:
                self.instrAlert.show()

        else:
            alert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(None, None, self, self.string("Cancel"), None)

            if section == "Maps":
                alert.setTitle_(self.string("Processing_Map"))
                alert.setMessage_(self.string("Processing_Map_Message") %
                    (self.dispMenu[ select ]["items"][row]["name"] , self.dispMenu[ select ]["items"][row]["info"]) )
                alert.addButtonWithTitle_(self.string("Link"))
                alert.addButtonWithTitle_(self.string("Copy"))

                progressFrame = ((25, 15), (25.0, 25.0))
                progressView1 = UIActivityIndicatorView.alloc().initWithFrame_(progressFrame)
                progressView1.setActivityIndicatorViewStyle_(0)
                progressView1.startAnimating()
                progressView1.setTag_(21)

                progressFrame = ((230, 15), (25.0, 25.0))
                progressView2 = UIActivityIndicatorView.alloc().initWithFrame_(progressFrame)
                progressView2.setActivityIndicatorViewStyle_(0)
                progressView2.startAnimating()
                progressView2.setTag_(22)

                alert.addSubview_(progressView1)
                alert.addSubview_(progressView2)
            elif section == "Routes":
                alert.setTitle_(self.string("Processing_Route"))
                alert.setMessage_(self.string("Processing_Route_Message") % self.dispMenu[ select ]["items"][row]["name"] )
                alert.addButtonWithTitle_(self.string("Copy"))
            elif section == "Cache Management":
                alert.setTitle_(self.string("Processing_Cammand"))
                alert.setMessage_(self.string("Processing_Cammand_Message") % self.dispMenu[ select ]["items"][row]["name"] )
                alert.addButtonWithTitle_(self.string("Ok"))
            
            alert.show()
            
    # (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
    @objc.signature("i@:@@")
    def tableView_editingStyleForRowAtIndexPath_(self, table, path):
        if path == None:
            return 0
            
        if path.section() != 0 and path.row() == 0:
            return 2
        else:
            return 1

    # (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
    @objc.signature("v@:@i@")
    def tableView_commitEditingStyle_forRowAtIndexPath_(self, table, style, path):
        if self.currentMenu != 0:
            return
    
        self.path = path        # saving it to make it accessible for delegated funct
        # If row is deleted, remove it from the list.
        if style == 1: #UITableViewCellEditingStyleDelete
            if path.section() == 1:
                retval = os.system("rm -fr " + self.userHomeDirectory() + "/Media/Maps/" + self.mapItems[path.row()]["name"])
                if retval == 0:
                    self.mapItems.remove(self.mapItems[path.row()])
                else:
                    self.iomsDisplayError(self.string("Error_Code") % str(retval))
                    return
                # Test ...
                if (os.path.islink("/var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb") == True) and (os.path.exists("/var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb") == False):
                    # which means the current Maps data is a broken symbolic link , we should delete the broken symbolic link
                    os.system("rm /var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb ; rm /var/mobile/Library/Preferences/com.apple.Maps.plist")
                    self.setApplicationBadge_("") # and clear the badge
            elif path.section() == 2:
                retval = os.system("rm -fr " + self.userHomeDirectory() + "/Media/Maps/" + self.routeItems[path.row()]["name"])
                if retval == 0:
                    self.routeItems.remove(self.routeItems[path.row()])
                else:
                    self.iomsDisplayError(self.string("Error_Code") % str(retval))
                    return

            # adjusting sections title
            if len(self.mapItems) == 1:
                self.mainMenu[1]["section"] = "Maps_Empty"
            if len(self.routeItems) == 1:
                self.mainMenu[2]["section"] = "Routes_Empty"
                
            self.table.deleteRowsAtIndexPaths_withRowAnimation_([path], 0)

        elif style == 2: #UITableViewCellEditingStyleInsert
            self.iomsDisplayImportAlert(path.section())
       
    @objc.signature("v@:@i")
    def alertView_clickedButtonAtIndex_(self, alert, button):

        select = self.path.section()
        row    = self.path.row()
            
        section = self.dispMenu[ select ]["section"]
        
        if alert == self.ImportAlert:
            # Import Alert Delegate

            # cancel button
            if button == 0:
                return
            
            # destination path
            path = self.userHomeDirectory() + "/Media/Maps"
            destMapRoute = os.path.join(path, alert.textField().text())

            if alert.textField().text() == "":
                UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("blank_name"), self.string("blank_name_Message"), None , self.string("Ok"), None).show()
                return
            
            if section[:6] == "Routes":
                if os.path.exists(destMapRoute):
                    UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Route_exists"), self.string("Route_exists_Message") % alert.textField().text() , None , self.string("Ok"), None).show()
                    return
                    
                os.system("cp /var/mobile/Library/Maps/Route.plist " + destMapRoute)

            elif section[:4] == "Maps":
                if os.path.exists(destMapRoute):
                    UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Map_exists"), self.string("Map_exists_Message") % alert.textField().text() , None , self.string("Ok"), None).show()
                    return
                    
                try:
                    os.makedirs(destMapRoute)
                except:
                    self.iomsDisplayError(self.string("Error_Creat_Folder") % destMapRoute)
                    return
                # to avoid the Map data is one of our Maps date which using symbolic link 
                if os.path.islink("/var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb"):
                    UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Symbolic_link"),self.string("Symbolic_link_Message"),None,self.string("Ok"),None).show()
                    return

                retval1 = os.system("mv /var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb " + destMapRoute)
                retval2 = os.system("mv /var/mobile/Library/Preferences/com.apple.Maps.plist " + destMapRoute)
                
                if (retval1 != 0) or (retval2 != 0):
                    self.iomsDisplayError(self.string("Error_Copy_Code") % ( str(retval1) , str(retval2)))
                    return
                # Make a symbolic link to the Maps, and avoid people report that is an error , when importing a Maps
                # the Maps goes blank :P
                MapTiles = os.path.join(destMapRoute,"MapTiles.sqlitedb")
                plist    = os.path.join(destMapRoute,"com.apple.Maps.plist")
                os.system("ln -s " + MapTiles + " /var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb")
                os.system("ln -s " + plist    + " /var/mobile/Library/Preferences/com.apple.Maps.plist")
                #os.system("chmod -R 755 " + destMaps) # is this necessary? 
                # self.iomsDisplayError("Todo")

            self.iomsPrepareItems()
            UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Import_Done"), self.string("Import_Done_Message") % alert.textField().text(), None , self.string("Ok"), None).show()
            
            self.table.setEditing_(False)
            self.iomsDisplayCurrentMenu()
            self.table.reloadData()
            
        elif alert == self.aboutAlert:
            # cancel button
            if button == 0:
                url = NSURL.alloc().initWithString_("http://code.google.com/p/iphoneofflinemap/")
                UIApplication.sharedApplication().openURL_(url)
                sys.exit()
            else:
                return
        elif alert == self.processAlert:
            # cancel button
            if button == 1:
                UIApplication.sharedApplication().launchApplicationWithIdentifier_suspended_("com.apple.Maps", False)
                sys.exit()

            else:
                return
        else:
            if section == "Infos":
                # cancel button
                if button == 0:
                    return
                # self.openURL_(NSUrl.alloc().initWithString_("http://code.google.com/p/iphoneofflinemap/"))
                
            else:
                if button == 1:
                    cmd = self.dispMenu[ select ]["items"][row]["action-1"]
                elif button == 2:
                    cmd = self.dispMenu[ select ]["items"][row]["action-2"]
                else:
                    return

                retval = os.system(cmd)

                if retval != 0:
                    self.iomsDisplayError(self.string("Error_Action_Code") % str(retval))
                    return

                if self.dispMenu[ select ]["items"][row]["badge"] != None:
                    self.setApplicationBadge_( self.dispMenu[ select ]["items"][row]["badge"] )
                if section != "Cache Management":
                    self.table.reloadData()
                    self.processAlert.show()
        
    @objc.signature("v@:@i")
    def navigationBar_buttonClicked_(self,navbar,button):
        self.table.deselectRowAtIndexPath_animated_(self.table.indexPathForSelectedRow(), False)
        if button == 1:
            # left button
            self.table.setEditing_animated_(False, False)

            if self.currentMenu == 0:
                self.currentMenu = 1
            else:
                self.currentMenu = 0
            self.iomsDisplayCurrentMenu()
            self.table.reloadData()
        else:
            # right button : edit
            if self.table.isEditing():
                # need to quit edition
                self.navbar.showLeftButton_withStyle_rightButton_withStyle_(self.string("More"), 0, self.string("Edit"), 0)

                # inserting import items
                self.mapItems.remove  ({ "name" : self.string("item_Map_Import") })
                self.routeItems.remove({ "name" : self.string("item_Route_Import") })

            else:
                # start edition
                self.navbar.showLeftButton_withStyle_rightButton_withStyle_(None, 0, self.string("Edit"), 2)
                
                # inserting import items
                self.mapItems.insert  (0, { "name" : self.string("item_Map_Import") })
                self.routeItems.insert(0, { "name" : self.string("item_Route_Import") })
            
            self.table.reloadData()
            self.table.setEditing_animated_(not self.table.isEditing(), False)

    def iomsDisplayError(self, message):
        UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Error"), message, None, self.string("Ok"), None).show()
    
    def iomsDisplayImportAlert(self, func):
        if func == 1:       # Map Import
            if not (os.path.exists("/var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb") and os.path.exists("/var/mobile/Library/Preferences/com.apple.Maps.plist")):
                UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Failed_Import_Map"), self.string("Failed_Import_Map_Message"), None , self.string("OK"), None).show()
                return
            self.ImportAlert.setTitle_(self.string("Import_Map"))
            self.ImportAlert.setMessage_(self.string("Import_Map_Message"))
            self.ImportAlert.textField().setText_("Maps_" + str(len(self.mapItems)))
        else:               # Route Import
            # check for an existing route
            if not os.path.exists("/var/mobile/Library/Maps/Route.plist"):
                UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Failed_Import_Route"), self.string("Failed_Import_Route_Message"), None , self.string("Ok"), None).show()
                return

            self.ImportAlert.setTitle_(self.string("Import_Route"))
            self.ImportAlert.setMessage_(self.string("Import_Route_Message"))
            self.ImportAlert.textField().setText_("Route" + str(len(self.routeItems)) + ".plist")

        self.ImportAlert.show()
            
    def iomsPrepareItems(self):

        # RAZ
        self.settingsMenu = []       # prepared settings menu
        self.mainMenu     = []       # prepared main menu

        self.mapItems   = []         # list of Maps
        self.routeItems = []         # list of Routes
        self.cmdItems   = []         # list of Setting Comands

        # default map
        default_MapTiles = "/var/mobile/Library/Caches/MapTiles/MapTiles.sqlitedb"
        default_plist = "/var/mobile/Library/Preferences/com.apple.Maps.plist"
        # Route Data
        default_Route = "/var/mobile/Library/Maps/Route.plist"
        
        # Commands
        rm1 = "rm -rf " + default_MapTiles
        rm2 = "rm -rf " + default_plist
        rmcmd = rm1 + ";"+ rm2
        cpcmd = "cp -r "
        lncmd = "ln -s "
        path = self.userHomeDirectory() + "/Media/Maps"
        if not os.path.exists( path ):
            os.makedirs( path )
        # MAIN MENU
        if os.path.isdir(path):
            dir_list = os.listdir( path )
            for name in dir_list:
                fullname = os.path.join( path, name )
                if os.path.isdir( fullname ):
                    MapTiles = os.path.join(fullname , "MapTiles.sqlitedb")
                    plist    = os.path.join(fullname , "com.apple.Maps.plist")
                    if os.path.exists( MapTiles ) and os.path.exists( plist ):     
                        # Actually MapTiles is larger than plist , so , I think we can only use Maptiles to represent the size 
                        # of the Maps or just counting the Maps folder by using os.path.getsize(fullname).
                        # size = os.path.getsize(MapTiles) + os.path.getsize(plist)
                        size = os.path.getsize( MapTiles ) / (1024*1024)
                        if size < 0:
                            sizeStr = "> 2Gb"
                        else:
                            sizeStr = str(size) + "Mb"
                        # and another things that I couldn't find the resolvent is the Long Integer problem, getsize return    
                        # the size, in bytes , so , I solve this problem by calculate the size with MB first , then return to  
                        # the variable. I hope this could work , because I don't have any Map larger than 200MB.

                        # i18n with CJK unicode support , this paragraph maybe not useful in Europe 
                        if os.path.exists( os.path.join(fullname , "badge")):# if badge is exists , readin and set to badgename
                            localize = open( os.path.join(fullname , "badge") , "r") 
                            local_badgename = unicode( localize.readline(),'UTF-8')
                            localize.close()
                            badgename = local_badgename # bagde set by user, sometimes 5 letters fit, so no restrictions
                        else:
                            badgename = name + '   '
                            badgename = badgename[:4]
                            
                        name = name + " [" + badgename + "]"
                        
                        #Branch end.
                        
                        #Copy Method
                        cmd1   = cpcmd + MapTiles + " " + default_MapTiles
                        cmd2   = cpcmd + plist    + " " + default_plist
                        final_cpcmd    = rmcmd + ";" + cmd1 + ";" + cmd2
                        #Link method
                        cmd1   = lncmd + MapTiles + " " + default_MapTiles
                        cmd2   = lncmd + plist    + " " + default_plist
                        final_lncmd    = rmcmd + ";" + cmd1 + ";" + cmd2
                        self.mapItems.append({"name" : name , "badge" : badgename , "info": sizeStr, "action-1" : final_lncmd ,"action-2" : final_cpcmd})
                else:
                    # if fullname is not a Maps Data, it must be a Route data.
                    cmd1   = "rm " +  default_Route + " ;" + cpcmd + fullname + " " + default_Route
                    self.routeItems.append({ "name" : name , "badge" : None ,"action-1" : cmd1 })
            self.mainMenu.append({"section" : "       " +  self.version  , "items" : [] })

            # lists are built, now we display them
            if self.mapItems != []:
                self.mainMenu.append({"section" : "Maps"   , "items" : self.mapItems })
            else:
                self.mainMenu.append({"section" : "Maps_Empty", "items" : self.mapItems })

            if self.routeItems != []:
                self.mainMenu.append({"section" : "Routes" , "items" : self.routeItems })
            else:
                self.mainMenu.append({"section" : "Routes_Empty", "items" : self.routeItems })
        
        # SETTINGS MENU
        self.cmdItems = [{"name" : self.string("Remove_All_Caches")  , "badge" : self.string("Clear") ,"action-1" : rmcmd   }, \
                         {"name" : self.string("Remove_Map_Caches")  , "badge" : self.string("Clear") ,"action-1" : rm1     }, \
                         {"name" : self.string("Remove_Badge")       , "badge" : ""      ,"action-1" : "true"  }]
                         
        # adding cache mgnt commands
        self.settingsMenu.append({"section" : "Cache Management" , "items" : self.cmdItems })
        # adding infos sectio
        self.settingsMenu.append({"section" : "Infos" , \
                                  "items" : [{"name" : self.string("Instructions"), "message" : self.string("Instructions_Message") }, \
                                             {"name" : self.string("About")       , "message" : (self.string("About_Message") % self.version_number)} ] })

    def iomsInit(self):
        print self.version
        print "--------------------------"

        # buidling static popups for later use  
        self.aboutAlert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("About"), (self.string("About_Message") % self.version_number ), self, self.string("Web_Site"), None)
        self.aboutAlert.addButtonWithTitle_(self.string("Ok"))

        self.instrAlert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Instructions"), self.string("Instructions_Message") , None, self.string("Ok"), None)

        self.processAlert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Process_Finish"), self.string("Process_Finish_Message"), self, self.string("Continue"), None)
        self.processAlert.addButtonWithTitle_(self.string("Launch_Maps"))

        
        # Import Alert
        self.ImportAlert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(None, None, self, self.string("Cancel"), None)
        self.ImportAlert.addButtonWithTitle_(self.string("Import"))
        self.ImportAlert.addTextFieldWithValue_label_(None, self.string("Output_Name"))
        self.ImportAlert.textField().setTextAlignment_(1)
        self.ImportAlert.textField().becomeFirstResponder()

        # init menus
        self.iomsPrepareItems()
        self.currentMenu = 0
        # Init the Map folder 
        # Maybe It should not be operated this each time , but I thought this may decreasing people makes wrong when they are 
        # using wrong permission. But owner problem is still not easy to correct while springboard runs with mobile account :(
        # Or , we should alert when we find the owner is incorrect .
        os.system("chmod -R 755 /var/mobile/Media/Maps")

    def iomsDisplayCurrentMenu(self):
        if self.currentMenu == 0:
            self.dispMenu = self.mainMenu
            navItem = self.navbar.popNavigationItemAnimated_(False)
            navItem.setTitle_(self.string("App_Title"))
            self.navbar.pushNavigationItem_(navItem)
            self.navbar.showLeftButton_withStyle_rightButton_withStyle_(self.string("More"), 0, self.string("Edit"), 0)

            if len(self.routeItems) + len(self.mapItems) == 0:
                UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles_(self.string("Instructions"), self.string("Instructions_Message") , None, self.string("Ok"), None).show()

        else:
            self.dispMenu = self.settingsMenu
            navItem = self.navbar.popNavigationItemAnimated_(False)
            navItem.setTitle_(self.string("More"))
            self.navbar.pushNavigationItem_(navItem)
            self.navbar.showLeftButton_withStyle_rightButton_withStyle_(self.string("Back"), 1, None, 0)
        
    @objc.signature("v@:@")
    def applicationDidFinishLaunching_(self, unused):
        # init 
        self.iomsInit()

        # init window.
        outer = UIHardware.fullScreenApplicationContentRect()
        self.window = UIWindow.alloc().initWithFrame_(outer)

        self.window.orderFront_(self)
        self.window.makeKey_(self)
        self.window._setHidden_(NO)

        inner = self.window.bounds()
        navsize = UINavigationBar.defaultSize()
        navrect = ((0, 0), (inner[1][0], navsize[1]))

        # init UIView
        self.view = UIView.alloc().initWithFrame_(self.window.bounds())
        self.window.setContentView_(self.view)

        # init Navi-bar
        self.navbar = UINavigationBar.alloc().initWithFrame_(navrect);
        self.view.addSubview_(self.navbar)
        self.navbar.setDelegate_(self)
        self.navbar.enableAnimation()
        self.navbar.setBarStyle_(0)
         
        navitem = UINavigationItem.alloc().initWithTitle_(self.string("App_Title"))
        self.navbar.pushNavigationItem_(navitem)

        # display menu
        self.iomsDisplayCurrentMenu()

        # init Table View
        lower = ((0, navsize[1]), (inner[1][0], inner[1][1] - navsize[1]));
        table = UITableView.alloc().initWithFrame_style_(lower, 1)

        
        self.table = table
        self.view.addSubview_(table)
        table.setSeparatorStyle_(1)
        table.setDelegate_(self)
        table.setDataSource_(self)

        table.setAllowsSelectionDuringEditing_(True)

        table.reloadData()
        
UIApplicationMain( principal = PYApplication )
